home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 7
/
Night Owl Shareware (NOPV7)(Night Owl Publisher Inc.)(1992).bin
/
038a
/
bash1_12.arj
/
BASH1-12.TAR
/
bash-1.12
/
builtins
/
cd.def
< prev
next >
Wrap
Text File
|
1991-12-31
|
15KB
|
589 lines
This file is cd.def, from which is created cd.c. It implements the
builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
$PRODUCES cd.c
#include <stdio.h>
#include <sys/param.h>
#include "../shell.h"
#include "../maxpath.h"
static int change_to_directory (), cd_to_string ();
/* Keeps track of the current working directory. */
extern char *the_current_working_directory;
/* By default, follow the symbolic links as if they were real directories
while hacking the `cd' command. This means that `cd ..' moves up in
the string of symbolic links that make up the current directory, instead
of the absolute directory. The shell variable `nolinks' controls this
flag. */
int follow_symbolic_links = 1;
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [dir]
Change the current directory to DIR. The variable $HOME is the
default DIR. The variable $CDPATH defines the search path for
the directory containing DIR. Alternative directory names are
separated by a colon (:). A null directory name is the same as
the current directory, i.e. `.'. If DIR begins with a slash (/),
then $CDPATH is not used. If the directory is not found, and the
shell variable `cdable_vars' exists, then try the word as a variable
name. If that variable has a value, then cd to the value of that
variable.
$END
int
cd_builtin (list)
WORD_LIST *list;
{
char *dirname;
{
extern int restricted;
if (restricted)
{
builtin_error ("Privileged command");
return (EXECUTION_FAILURE);
}
}
if (list)
{
char *extract_colon_unit ();
char *path_string = get_string_value ("CDPATH");
char *path;
int index = 0;
dirname = list->word->word;
if (path_string && !absolute_pathname (dirname))
{
while ((path = extract_colon_unit (path_string, &index)))
{
char *dir;
if (*path && (*path == '~'))
{
char *tilde_expand (), *te_string = tilde_expand (path);
free (path);
path = te_string;
}
if (!*path)
{
free (path);
path = savestring ("."); /* by definition. */
}
dir = (char *)alloca (2 + strlen (dirname) + strlen (path));
if (!dir)
fatal_error ("Out of memory");
strcpy (dir, path);
if (path[strlen (path) - 1] != '/')
strcat (dir, "/");
strcat (dir, dirname);
free (path);
if (change_to_directory (dir))
{
if (strncmp (dir, "./", 2) != 0)
printf ("%s\n", dir);
dirname = dir;
goto bind_and_exit;
}
}
}
if (!change_to_directory (dirname))
{
/* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
if (dirname[0] == '-' && dirname[1] == '\0')
{
char *t = get_string_value ("OLDPWD");
if (t && change_to_directory (t))
goto bind_and_exit;
}
/* If the user requests it, then perhaps this is the name of
a shell variable, whose value contains the directory to
change to. If that is the case, then change to that
directory. */
if (find_variable ("cdable_vars"))
{
char *t = get_string_value (dirname);
if (t && change_to_directory (t))
{
printf ("%s\n", t);
goto bind_and_exit;
}
}
file_error (dirname);
return (EXECUTION_FAILURE);
}
goto bind_and_exit;
}
else
{
dirname = get_string_value ("HOME");
if (!dirname)
return (EXECUTION_FAILURE);
if (!change_to_directory (dirname))
{
file_error (dirname);
return (EXECUTION_FAILURE);
}
bind_and_exit:
{
char *get_working_directory (), *get_string_value ();
char *directory = get_working_directory ("cd");
bind_variable ("OLDPWD", get_string_value ("PWD"));
bind_variable ("PWD", directory);
if (directory)
free (directory);
}
return (EXECUTION_SUCCESS);
}
}
$BUILTIN pwd
$FUNCTION pwd_builtin
$SHORT_DOC pwd
Print the current working directory.
$END
/* Non-zero means that pwd always give verbatim directory, regardless of
symbolic link following. */
static int verbatim_pwd = 1;
/* Print the name of the current working directory. */
pwd_builtin (list)
WORD_LIST *list;
{
char *get_working_directory (), *getwd (), *directory;
no_args (list);
if (verbatim_pwd)
{
char *buffer = (char *)xmalloc (MAXPATHLEN);
directory = getwd (buffer);
if (!directory)
{
builtin_error ("%s", buffer);
free (buffer);
}
}
else
{
directory = get_working_directory ("pwd");
}
if (directory)
{
printf ("%s\n", directory);
fflush (stdout);
free (directory);
return (EXECUTION_SUCCESS);
}
else
return (EXECUTION_FAILURE);
}
$BUILTIN pushd
$FUNCTION pushd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC pushd [dir | +n | -n]
Adds a directory to the top of the directory stack, or rotates
the stack, making the new top of the stack the current working
directory. With no arguments, exchanges the top two directories.
+n Rotates the stack so that the Nth directory (counting
from the left of the list shown by `dirs') is at the top.
-n Rotates the stack so that the Nth directory (counting
from the right) is at the top.
dir adds DIR to the directory stack at the top, making it the
new current working directory.
You can see the directory stack with the `dirs' command.
If the variable `pushd_silent' is not set and the pushd command
was successful, a `dirs' is be performed as well.
$END
#if defined (PUSHD_AND_POPD)
/* Some useful commands whose behaviour has been observed in Csh. */
/* The list of remembered directories. */
static char **pushd_directory_list = (char **)NULL;
/* Number of existing slots in this list. */
static int directory_list_size = 0;
/* Offset to the end of the list. */
static int directory_list_offset = 0;
pushd_builtin (list)
WORD_LIST *list;
{
char *temp, *current_directory, *get_working_directory ();
int j = directory_list_offset - 1;
char direction = '+';
/* If there is no argument list then switch current and
top of list. */
if (!list)
{
if (!directory_list_offset)
{
builtin_error ("No other directory");
return (EXECUTION_FAILURE);
}
current_directory = get_working_directory ("pushd");
if (!current_directory)
return (EXECUTION_FAILURE);
temp = pushd_directory_list[j];
pushd_directory_list[j] = current_directory;
goto change_to_temp;
}
else
{
direction = *(list->word->word);
if (direction == '+' || direction == '-')
{
int num;
if (1 == sscanf (&(list->word->word)[1], "%d", &num))
{
if (direction == '-')
num = directory_list_offset - num;
if (num > directory_list_offset || num < 0)
{
if (!directory_list_offset)
builtin_error ("Directory stack empty");
else
builtin_error ("Stack contains only %d directories",
directory_list_offset + 1);
return (EXECUTION_FAILURE);
}
else
{
/* Rotate the stack num times. Remember, the
current directory acts like it is part of the
stack. */
temp = get_working_directory ("pushd");
if (!num)
goto change_to_temp;
do
{
char *top =
pushd_directory_list[directory_list_offset - 1];
for (j = directory_list_offset - 2; j > -1; j--)
pushd_directory_list[j + 1] = pushd_directory_list[j];
pushd_directory_list[j + 1] = temp;
temp = top;
num--;
}
while (num);
temp = savestring (temp);
change_to_temp:
{
int tt = EXECUTION_FAILURE;
if (temp)
{
tt = cd_to_string (temp);
free (temp);
}
if ((tt == EXECUTION_SUCCESS) &&
(!find_variable ("pushd_silent")))
dirs_builtin ((WORD_LIST *)NULL);
return (tt);
}
}
}
}
/* Change to the directory in list->word->word. Save the current
directory on the top of the stack. */
current_directory = get_working_directory ("pushd");
if (!current_directory)
return (EXECUTION_FAILURE);
if (cd_builtin (list) == EXECUTION_SUCCESS)
{
if (directory_list_offset == directory_list_size)
{
pushd_directory_list = (char **)
xrealloc (pushd_directory_list,
(directory_list_size += 10) * sizeof (char *));
}
pushd_directory_list[directory_list_offset++] = current_directory;
if (!find_variable ("pushd_silent"))
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
else
{
free (current_directory);
return (EXECUTION_FAILURE);
}
}
}
#endif /* PUSHD_AND_POPD */
$BUILTIN dirs
$FUNCTION dirs_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC dirs [-l]
Display the list of currently remembered directories. Directories
find their way onto the list with the `pushd' command; you can get
back up through the list with the `popd' command.
The -l flag specifies that `dirs' should not print shorthand versions
of directories which are relative to your home directory. This means
that `~/bin' might be displayed as `/homes/bfox/bin'.
$END
#if defined (PUSHD_AND_POPD)
/* Print the current list of directories on the directory stack. */
dirs_builtin (list)
WORD_LIST *list;
{
register int i, format = 0;
char *temp, *polite_directory_format (), *get_working_directory ();
/* Maybe do long form? */
if (list)
{
if (strcmp (list->word->word, "-l") == 0)
format++;
else if (!format || list->next)
{
bad_option (list->word->word);
return (EXECUTION_FAILURE);
}
}
/* The first directory printed is always the current working directory. */
temp = get_working_directory ("dirs");
if (!temp)
temp = savestring ("<no directory>");
printf ("%s", format ? temp : polite_directory_format (temp));
free (temp);
/* Now print any directories in the array. */
for (i = (directory_list_offset - 1); i > -1; i--)
printf (" %s", format ? pushd_directory_list[i] :
polite_directory_format (pushd_directory_list[i]));
putchar ('\n');
fflush (stdout);
return (EXECUTION_SUCCESS);
}
#endif /* PUSHD_AND_POPD */
$BUILTIN popd
$FUNCTION popd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC popd [+n | -n]
Removes entries from the directory stack. With no arguments,
removes the top directory from the stack, and cd's to the new
top directory.
+n removes the Nth entry counting from the left of the list
shown by `dirs', starting with zero. For example: `popd +0'
removes the first directory, `popd +1' the second.
-n removes the Nth entry counting from the right of the list
shown by `dirs', starting with zero. For example: `popd -0'
removes the last directory, `popd -1' the next to last.
You can see the directory stack with the `dirs' command.
If the variable 'pushd_silent' is not set and the popd command
was successful, a 'dirs' will be performed as well..
$END
#if defined (PUSHD_AND_POPD)
/* Pop the directory stack, and then change to the new top of the stack.
If LIST is non-null it should consist of a word +N or -N, which says
what element to delete from the stack. The default is the top one. */
popd_builtin (list)
WORD_LIST *list;
{
register int i;
int which = 0;
char direction = '+';
if (list)
{
direction = *(list->word->word);
if ((direction != '+' && direction != '-') ||
(1 != sscanf (&((list->word->word)[1]), "%d", &which)))
{
builtin_error ("bad arg `%s'", list->word->word);
return (EXECUTION_FAILURE);
}
}
if (which > directory_list_offset || (!directory_list_offset && !which))
{
if (!directory_list_offset)
builtin_error ("Directory stack empty");
else
builtin_error ("Stack contains only %d directories",
directory_list_offset + 1);
return (EXECUTION_FAILURE);
}
/* Handle case of no specification, or top of stack specification. */
if ((direction == '+' && which == 0) ||
(direction == '-' && which == directory_list_offset))
{
i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
if (i != EXECUTION_SUCCESS)
return (i);
free (pushd_directory_list[--directory_list_offset]);
}
else
{
/* Since an offset other than the top directory was specified,
remove that directory from the list and shift the remainder
of the list into place. */
if (direction == '+')
i = directory_list_offset - which;
else
i = which;
free (pushd_directory_list[i]);
directory_list_offset--;
/* Shift the remainder of the list into place. */
for (; i < directory_list_offset; i++)
pushd_directory_list[i] = pushd_directory_list[i + 1];
}
if (!find_variable ("pushd_silent"))
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
#endif /* PUSHD_AND_POPD */
/* Do the work of changing to the directory NEWDIR. Handle symbolic
link following, etc. */
static int
change_to_directory (newdir)
char *newdir;
{
char *get_working_directory (), *make_absolute ();
char *t;
if (follow_symbolic_links)
{
if (!the_current_working_directory)
{
t = get_working_directory ("cd_links");
if (t)
free (t);
}
if (the_current_working_directory)
t = make_absolute (newdir, the_current_working_directory);
else
t = savestring (newdir);
/* Get rid of trailing `/'. */
{
register int len_t = strlen (t);
if (len_t > 1)
{
--len_t;
if (t[len_t] == '/')
t[len_t] = '\0';
}
}
if (chdir (t) < 0)
{
free (t);
return (0);
}
if (the_current_working_directory)
strcpy (the_current_working_directory, t);
free (t);
return (1);
}
else
{
if (chdir (newdir) < 0)
return (0);
else
return (1);
}
}
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
so if the result is EXECUTION_FAILURE then an error message has already
been printed. */
static int
cd_to_string (name)
char *name;
{
extern WORD_LIST *make_word_list ();
WORD_LIST *tlist = make_word_list (make_word (name), NULL);
int result = (cd_builtin (tlist));
dispose_words (tlist);
return (result);
}